package cn.com.enersun.iec61850.integratedDataProcessing;

import cn.com.enersun.iec61850.web.domain.DeviceList;
import cn.com.enersun.iec61850.web.domain.ServerModelStructure;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openmuc.jositransport.TConnection;
import org.openmuc.openiec61850.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.util.*;


/**
 * Created by YYC on 2017/4/1.
 */
public class ClientDataProcessing  {
    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(ClientDataProcessing.class);

    private Map<String, ServerModel> clientServerModels;
    private Map<String, ClientAssociation> clientAssociations;
    private IntegratedDataProcessing integratedDataProcessing;

    public ClientDataProcessing(Map<String, ServerModel> clientServerModels, Map<String, ClientAssociation> clientAssociations, IntegratedDataProcessing integratedDataProcessing) {
        this.clientServerModels = clientServerModels;
        this.clientAssociations = clientAssociations;
        this.integratedDataProcessing = integratedDataProcessing;
    }

    /**
     * @function 查找数据库在线监测装置列表与ServerModel与在线监测设备进行关联
     */
    public void addClientAssociationByDatabase(List<DeviceList> deviceLists) {
        //List<ClientSap> clientSap = new ArrayList<ClientSap>();
        // alternatively you could use ClientSap(SocketFactory factory) to e.g. connect using SSL
        // optionally you can set some association parameters (but usually the default should work):
        // clientSap.setTSelRemote(new byte[] { 0, 1 });
        // clientSap.setTSelLocal(new byte[] { 0, 0 });
        //ClientDataProcessing eventHandler = new ClientDataProcessing();
        //this.association = new ArrayList<ClientAssociation>();
        if ((deviceLists == null) || deviceLists.isEmpty()) {
            return;
        }

        for (DeviceList deviceList : deviceLists) {
            try {
                    clientAssociations.put(deviceList.getDevIp(), new ClientSap().associate(
                            InetAddress.getByName(deviceList.getDevIp()), deviceList.getDevPort(),
                            null));
                    integratedDataProcessing.updateDeviceStatus(deviceList.getDevIp(), true);
                    logger.info("Attempting to connect to server " + deviceList.getDevIp() + " on port " + deviceList.getDevPort());
                } catch (IOException e) {
                    // an IOException will always indicate a fatal exception. It indicates that the association was closed and
                    // cannot be recovered. You will need to create a new association using ClientSap.associate() in order to
                    // reconnect.
                    logger.error("Error connecting to server: " + e.getMessage());
                    integratedDataProcessing.updateDeviceStatus(deviceList.getDevIp(), false);
                    continue;
                    //return;
                }
            }

            if (clientAssociations == null || clientAssociations.size() == 0) {
                logger.error("Error connecting to server, clientAssociations is empty!");
                return;
            }

            //获取ServerModel
        for (String key : clientAssociations.keySet()) {
            try {

                /*
                //如果数据库中没有ServerModel的结构数据，则从网络获取
                if((integratedDataProcessing.getModelLeafByDatabase(key) == null) || (integratedDataProcessing.getModelLeafByDatabase(key).isEmpty())) {
                    clientServerModels.put(key, clientAssociations.get(key).retrieveModel());
                    clientAssociations.get(key).updateDataSets();
                    //将获取模型存入数据库
                    this.SerModelToModelStructure(key, clientServerModels.get(key));
                }else {
                    //从数据库导入模型
                    clientAssociations.get(key).serverModel = ModelStructureToSerModel(key);
                    clientServerModels.put(key, clientServerModels.get(key));
                    //clientAssociations.get(key).updateDataSets();
                }
                */
                clientServerModels.put(key, clientAssociations.get(key).retrieveModel());
                clientAssociations.get(key).updateDataSets();
            } catch (IOException e) {
                logger.error("Fatal IOException requesting model.", e);
                continue;
            } catch (Exception e) {
                logger.error("Fatal Exception requesting model.", e);
                continue;
            }
        }

        // get the values of all data attributes in the model:
        for (String key : clientAssociations.keySet()) {
            try {
                clientAssociations.get(key).getAllDataValues();
            } catch (Exception ex) {
                logger.error("Error get data values.", ex);
            }
        }
        for (String key : clientServerModels.keySet()) {
            for (BasicDataAttribute bda : clientServerModels.get(key).getBasicDataAttributes()) {
                logger.info("BDA: " + bda);
            }

            for (Urcb urcb : clientServerModels.get(key).getUrcbs()) {
                logger.info("URCB: " + urcb);
            }

            for (Brcb brcb : clientServerModels.get(key).getBrcbs()) {
                logger.info("BRCB: " + brcb);
            }
        }
    }

    private ServerModel ModelStructureToSerModel(String devName) throws Exception {
        //////////////  数据模型的处理 /////////////////
        //第一步：得到所有的BasicDataAttribute，即数据属性
        List<ServerModelStructure> bdaModelStructures = integratedDataProcessing.getModelLeafByDatabase(devName);
        Map<String,ArrayList<ServerModelStructure>> bdasClassify = classify(bdaModelStructures);
        Map<String, List<FcModelNode>> basicDataAttributes = this.ModelStructuresToBda(bdasClassify);

        //第二步：得到所有的FcDataObject、Urcb、Brcb，即数据对象
        Map<String, List<FcDataObject>> dataObjects = new HashMap<String, List<FcDataObject>>();
        //得到功能约束的数据集合
        List<ServerModelStructure> fcDataModelStructures = integratedDataProcessing.getModelByDatabase(devName, "DataModel", "org.openmuc.openiec61850.FcDataObject");
        Map<String,ArrayList<ServerModelStructure>> fcDataClassify = classify(fcDataModelStructures);
        //建立constructedDAStructures是为了除了数据属性下还有数据属性的情况，ConstructedDataAttribute为处理数据属性下还有数据属性类
        List<ServerModelStructure> constructedDAStructures = integratedDataProcessing.getModelByDatabase(devName, "DataModel", "org.openmuc.openiec61850.ConstructedDataAttribute");
        Map<String,ArrayList<ServerModelStructure>> fcConstructedClassify = classify(constructedDAStructures);
        Map<String, List<FcModelNode>> constructedDataAttributes = new HashMap<String, List<FcModelNode>>();
        //判读是否有属性下还有属性的节点
        if(!((fcConstructedClassify == null) || fcConstructedClassify.isEmpty())) {
            for (String fcConstructedkey : fcConstructedClassify.keySet()) {
                List<FcModelNode> constructedBasicDataAttributes = new LinkedList<FcModelNode>();
                for (int i = 0; i < fcConstructedClassify.get(fcConstructedkey).size(); i++) {
                    ObjectReference reference = new ObjectReference(fcConstructedClassify.get(fcConstructedkey).get(i).getParentReference() + "." + fcConstructedClassify.get(fcConstructedkey).get(i).getNodeName());
                    constructedBasicDataAttributes.add(new ConstructedDataAttribute(
                            reference,
                            Fc.fromString(fcConstructedClassify.get(fcConstructedkey).get(i).getNodeFc()),
                            //bda将父级路径作为key，可方便在父级添加子集数据，这里将数据对象的引用作为数据属性的key去查找数据属性集合
                            basicDataAttributes.get(reference.toString())
                    ));
                }
                constructedDataAttributes.put(fcConstructedkey, constructedBasicDataAttributes);
            }
        }
        for(String key : fcDataClassify.keySet()) {
            List<FcDataObject> fcDataObjects = new LinkedList<FcDataObject>();
            for(int i = 0; i < fcDataClassify.get(key).size(); i++) {
                ObjectReference reference = new ObjectReference(fcDataClassify.get(key).get(i).getParentReference() + "." + fcDataClassify.get(key).get(i).getNodeName());
                fcDataObjects.add(new FcDataObject(
                        reference,
                        Fc.fromString(fcDataClassify.get(key).get(i).getNodeFc()),
                        //bda将父级路径作为key，可方便在父级添加子集数据，这里将数据对象的引用作为数据属性的key去查找数据属性集合
                        basicDataAttributes.get(reference.toString())
                ));
                //过滤掉数据对象的数据属性下没有数据属性的情况
                if(!(constructedDataAttributes.get(reference.toString()) == null)) {
                    fcDataObjects.add(new FcDataObject(
                            reference,
                            Fc.fromString(fcDataClassify.get(key).get(i).getNodeFc()),
                            constructedDataAttributes.get(reference.toString())
                    ));
                }
            }
            dataObjects.put(key, fcDataObjects);
        }
        //得到未缓冲报告控制块的数据集合
        List<ServerModelStructure> urcbModelStructures = integratedDataProcessing.getModelByDatabase(devName, "DataModel", "org.openmuc.openiec61850.Urcb");
        Map<String,ArrayList<ServerModelStructure>> urcbClassify = classify(urcbModelStructures);
        for(String key : urcbClassify.keySet()) {
            List<FcDataObject> urcbDataObjects = new LinkedList<FcDataObject>();
            for(int i = 0; i < urcbClassify.get(key).size(); i++) {
                ObjectReference reference = new ObjectReference(urcbClassify.get(key).get(i).getParentReference() + "." + urcbClassify.get(key).get(i).getNodeName());
                urcbDataObjects.add(new Urcb(
                        reference,
                        basicDataAttributes.get(reference.toString())
                ));
            }
            //dataObjects.put(key, urcbDataObjects);
            if((dataObjects.get(key) == null) || dataObjects.get(key).isEmpty()) {
                dataObjects.put(key, urcbDataObjects);
            }else {
                dataObjects.get(key).addAll(urcbDataObjects);
            }
        }
        //得到缓冲报告控制块的数据集合
        List<ServerModelStructure> brcbModelStructures = integratedDataProcessing.getModelByDatabase(devName, "DataModel", "org.openmuc.openiec61850.Brcb");
        Map<String,ArrayList<ServerModelStructure>> brcbClassify = classify(brcbModelStructures);
        for(String key : brcbClassify.keySet()) {
            List<FcDataObject> brcbDataObjects = new LinkedList<FcDataObject>();
            for(int i = 0; i < brcbClassify.get(key).size(); i++) {
                ObjectReference reference = new ObjectReference(brcbClassify.get(key).get(i).getParentReference() + "." + brcbClassify.get(key).get(i).getNodeName());
                brcbDataObjects.add(new Brcb(
                        reference,
                        basicDataAttributes.get(reference.toString())
                ));
            }
            if((dataObjects.get(key) == null) || dataObjects.get(key).isEmpty()) {
                dataObjects.put(key, brcbDataObjects);
            }else {
                dataObjects.get(key).addAll(brcbDataObjects);
            }
        }
        //第三步：得到所有的逻辑节点
        Map<String, List<LogicalNode>> logicalNodes = new HashMap<String, List<LogicalNode>>();
        List<ServerModelStructure> nodeModelStructures = integratedDataProcessing.getModelByDatabase(devName, "DataModel", "org.openmuc.openiec61850.LogicalNode");
        Map<String,ArrayList<ServerModelStructure>> nodeClassify = classify(nodeModelStructures);
        for(String key : nodeClassify.keySet()) {
            List<LogicalNode> subLogicalNodes = new LinkedList<LogicalNode>();
            for(int i = 0; i < nodeClassify.get(key).size(); i++) {
                ObjectReference reference = new ObjectReference(nodeClassify.get(key).get(i).getParentReference() + "/" + nodeClassify.get(key).get(i).getNodeName());
                subLogicalNodes.add(new LogicalNode(
                        reference,
                        dataObjects.get(reference.toString())
                ));
            }
            logicalNodes.put(key, subLogicalNodes);
        }
        //第四步：得到所有的逻辑设备
        List<LogicalDevice> logicalDevices = new LinkedList<LogicalDevice>();
        List<ServerModelStructure> deviceModelStructures = integratedDataProcessing.getModelByDatabase(devName, "DataModel", "org.openmuc.openiec61850.LogicalDevice");
        for(ServerModelStructure key : deviceModelStructures) {
            ObjectReference reference = new ObjectReference(key.getNodeName());
            logicalDevices.add(new LogicalDevice(
                    reference,
                    logicalNodes.get(reference.toString())
            ));
        }
        ServerModel serverModel = new ServerModel(logicalDevices, null);

        //////////////  数据集的处理 /////////////////
        List<ServerModelStructure> dataSetModelStructures = integratedDataProcessing.getModelByDatabase(devName, "DataSets", "org.openmuc.openiec61850.DataSet");
        fcDataModelStructures = integratedDataProcessing.getDataSetDoByDatabase(devName);
        Map<String,ArrayList<ServerModelStructure>> fcDoClassify = classify(fcDataModelStructures);
        List<DataSet> dataSets = new LinkedList<DataSet>();
        for(ServerModelStructure serverModelStructure: dataSetModelStructures) {
            List<FcModelNode> fcModelNodes = new LinkedList<FcModelNode>();
            for(ServerModelStructure fcServerModelStructure : fcDoClassify.get(serverModelStructure.getParentReference() + "/" + serverModelStructure.getNodeName())) {
                ModelNode fcDo = serverModel.findModelNode(fcServerModelStructure.getNodeName(), Fc.fromString(fcServerModelStructure.getNodeFc()));
                if(fcDo == null) {
                    throw new Exception(fcServerModelStructure.getNodeName() + "数据对象未找到");
                } else {
                    fcModelNodes.add((FcModelNode) fcDo);
                }
            }

            dataSets.add(new DataSet(serverModelStructure.getParentReference() + "/" + serverModelStructure.getNodeName(), fcModelNodes));
        }
        serverModel.addDataSets(dataSets);

        return serverModel;
    }
    /**
     * 将ServerModelStructure中hasChild为null的记录转化为BasicDataAttribute
     * @param bdasClassify
     * @return
     * @throws Exception
     */
    private Map<String, List<FcModelNode>> ModelStructuresToBda(Map<String,ArrayList<ServerModelStructure>> bdasClassify) throws Exception {
        Map<String, List<FcModelNode>> basicDataAttributes = new HashMap<String, List<FcModelNode>>();
        for(String key : bdasClassify.keySet()) {
            List<FcModelNode> subBdas = new ArrayList<FcModelNode>();
            for(int i = 0; i < bdasClassify.get(key).size(); i++) {
                //Class c = Class.forName(bdasClassify.get(key).get(i).getNodeClass());
                //subBdas.add(c.newInstance());
                if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaInt8")) {
                    subBdas.add(new BdaInt8(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaInt8U")) {
                    subBdas.add(new BdaInt8U(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }
                if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaInt16")) {
                    subBdas.add(new BdaInt16(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false

                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaInt16U")) {
                    subBdas.add(new BdaInt16U(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaInt32")) {
                    subBdas.add(new BdaInt32(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaInt32U")) {
                    subBdas.add(new BdaInt32U(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }
                if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaInt64")) {
                    subBdas.add(new BdaInt64(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaFloat32")) {
                    subBdas.add(new BdaFloat32(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaFloat64")) {
                    subBdas.add(new BdaFloat64(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaBoolean")) {
                    subBdas.add(new BdaBoolean(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaCheck")) {
                    subBdas.add(new BdaCheck(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName())
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaDoubleBitPos")) {
                    subBdas.add(new BdaDoubleBitPos(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaEntryTime")) {
                    subBdas.add(new BdaEntryTime(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaOctetString")) {
                    subBdas.add(new BdaOctetString(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            30,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaOptFlds")) {
                    subBdas.add(new BdaOptFlds(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName())
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaQuality")) {
                    subBdas.add(new BdaQuality(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaReasonForInclusion")) {
                    subBdas.add(new BdaReasonForInclusion(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName())
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaTapCommand")) {
                    subBdas.add(new BdaTapCommand(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaTimestamp")) {
                    subBdas.add(new BdaTimestamp(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            false,
                            false
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaTriggerConditions")) {
                    subBdas.add(new BdaTriggerConditions(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName())
                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaUnicodeString")) {
                    subBdas.add(new BdaUnicodeString(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            50,
                            false,
                            false

                    ));
                    continue;
                }else if(bdasClassify.get(key).get(i).getNodeClass().contains("BdaVisibleString")) {
                    subBdas.add(new BdaVisibleString(
                            new ObjectReference(bdasClassify.get(key).get(i).getParentReference() + "." + bdasClassify.get(key).get(i).getNodeName()),
                            Fc.fromString(bdasClassify.get(key).get(i).getNodeFc()),
                            null,
                            20,
                            false,
                            false

                    ));
                    continue;
                }else {
                    throw new Exception("发现数据库内存在未被处理的类型" + bdasClassify.get(key).get(i).getNodeClass());
                }
            }
            basicDataAttributes.put(key, subBdas);
        }
        return basicDataAttributes;
    }
    /**
     * 将List中的对象按照某个属性进行归类，形成LinkedHashMap<String, List>
     * @param list
     */
    private Map<String,ArrayList<ServerModelStructure>>  classify(List list){
        TreeMap tm=new TreeMap();
        for(int i=0;i<list.size();i++){
            ServerModelStructure s=(ServerModelStructure) list.get(i);
            if(tm.containsKey(s.getParentReference())){
                ArrayList l11=(ArrayList)tm.get(s.getParentReference());
                l11.add(s);
            }else{
                ArrayList tem=new ArrayList();
                tem.add(s);
                tm.put(s.getParentReference(), tem);
            }

        }
        return tm;
    }
    private LinkedHashMap<String, List<ServerModelStructure>> classify(List<ServerModelStructure> list, String keyName)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        LinkedHashMap<String, List<ServerModelStructure>> target = new LinkedHashMap();
        for (Object obj : list) {
            // 取得需要归类的属性（keyName）的值，不做类型转换
            //Object oKeyValue = PropertyUtils.getProperty(obj, keyName);
            Object oKeyValue = BeanUtils.getPropertyDescriptor(obj.getClass(), keyName);
            String keyValue = String.valueOf(oKeyValue);
            if (!target.containsKey(keyValue)) {
                // 如果map中没有归类key值，则添加key值和相应的list
                ArrayList keyList = new ArrayList();
                keyList.add(obj);
                target.put(keyValue, keyList);
            } else {
                // 如果有归类key值，则在相应的list中添加这个bean
                ArrayList keyList = (ArrayList) target.get(keyValue);
                keyList.add(obj);
            }
        }
        return target;
    }
    //迭代添加子节点
    private void SerModelToModelStructure(String devName, ServerModel serverModel) throws Exception{
        //处理数据模型里面的数据
        for(ModelNode logicalDevice : serverModel.getChildren()) {
            integratedDataProcessing.insertModelStructure(new ServerModelStructure(
                    devName,
                    "DataModel",
                    null,
                    ! ((logicalDevice.getChildren()==null) || (logicalDevice.getChildren().isEmpty())),
                    logicalDevice.getName(),
                    logicalDevice.getClass().getName(),
                    null));
            for(ModelNode logicalNode : logicalDevice.getChildren()) {
                integratedDataProcessing.insertModelStructure(new ServerModelStructure(
                        devName,
                        "DataModel",
                        logicalNode.getParent().getReference().toString(),
                        ! ((logicalNode.getChildren()==null) || (logicalNode.getChildren().isEmpty())),
                        logicalNode.getName(),
                        logicalNode.getClass().getName(),
                        null));
                for(ModelNode dataObject : logicalNode.getChildren()) {
                    integratedDataProcessing.insertModelStructure(new ServerModelStructure(
                            devName,
                            "DataModel",
                            dataObject.getParent().getReference().toString(),
                            ! ((dataObject.getChildren()==null) || (dataObject.getChildren().isEmpty())),
                            dataObject.getName(),
                            dataObject.getClass().getName(),
                            ((FcDataObject) dataObject).getFc().toString()));
                    //数据对象下可能是数据属性或者是子数据对象，即DO下可是DA或subDO
                    for(ModelNode node : dataObject.getChildren()) {
                        this.storageIterative("DataModel", devName, node);
                    }
                }
            }
        }
        //处理数据集里面的数据
        for(DataSet dataSet : serverModel.getDataSets()) {
            integratedDataProcessing.insertModelStructure(new ServerModelStructure(
                    devName,
                    "DataSets",
                    dataSet.getReferenceStr().split("/")[0],
                    ! dataSet.getMembers().isEmpty(),
                    dataSet.getReferenceStr().split("/")[1],
                    dataSet.getClass().getName(),
                    null));
            //处理数据对象
            for(FcModelNode dataObject : dataSet.getMembers()) {
                integratedDataProcessing.insertModelStructure(new ServerModelStructure(
                        devName,
                        "DataSets",
                        dataSet.getReferenceStr(),
                        !((dataObject.getChildren()==null) || (dataObject.getChildren().isEmpty())) ,
                        dataObject.getReference().toString(),
                        dataObject.getClass().getName(),
                        dataObject.getFc().toString()));
            }
        }
    }
    private void storageIterative(String moduleName, String devName, ModelNode node) throws Exception{
        if((node.getChildren() == null) || (node.getChildren().isEmpty())) {
            integratedDataProcessing.insertModelStructure(new ServerModelStructure(
                    devName,
                    moduleName,
                    node.getParent().getReference().toString(),
                    null,
                    node.getName(),
                    node.getClass().getName(),
                    //FcDataObject和BasicDataAttribute都继承FcModelNode
                    ((FcModelNode) node).getFc().toString()));
            return;
        }else {
            integratedDataProcessing.insertModelStructure(new ServerModelStructure(
                    devName,
                    moduleName,
                    node.getParent().getReference().toString(),
                    ! ((node.getChildren()==null) || (node.getChildren().isEmpty())),
                    node.getName(),
                    node.getClass().getName(),
                    //FcDataObject和BasicDataAttribute都继承FcModelNode
                    ((FcModelNode) node).getFc().toString()));
            for (ModelNode subNode : node.getChildren()) {
                this.storageIterative(moduleName, devName, subNode);
            }
        }
    }

    /**
     * @function 与在线监测装置连接后通过网络获取ServerModel进行关联
     * @param addr
     * @param port
     */
    public void addClientAssociation(InetAddress addr, int port) throws Exception {
        //List<ClientSap> clientSap = new ArrayList<ClientSap>();
        // alternatively you could use ClientSap(SocketFactory factory) to e.g. connect using SSL
        // optionally you can set some association parameters (but usually the default should work):
        // clientSap.setTSelRemote(new byte[] { 0, 1 });
        // clientSap.setTSelLocal(new byte[] { 0, 0 });
        //ClientDataProcessing eventHandler = new ClientDataProcessing();
        //this.association = new ArrayList<ClientAssociation>();
        if(clientAssociations.containsKey(addr.getHostAddress())) {
            throw new Exception(addr.getHostAddress()  + ":" + port + "已经存在");
        }
        try {
            clientAssociations.put(addr.getHostAddress(), new ClientSap().associate(addr, port, null));
            logger.info("Attempting to connect to server " + addr.toString() + " on port " + port);
            /*
            for(int i = 0; i < address.size(); i++){
                association.add(clientSap.associate(address.get(i), remotePort, null, eventHandler));
            }*/
        } catch (IOException e) {
            // an IOException will always indicate a fatal exception. It indicates that the association was closed and
            // cannot be recovered. You will need to create a new association using ClientSap.associate() in order to
            // reconnect.
            logger.error("Error connecting to server" + addr.getHostAddress() + ":" + e.getMessage());
            if(integratedDataProcessing.selectDevice(addr.getHostAddress()) == null) {
                integratedDataProcessing.insertDevice(new DeviceList(addr.getHostAddress(), addr.getHostAddress(),port,false));
            }
            throw new Exception("错误连接到服务," + e.getMessage());
        }

        if (clientAssociations == null || clientAssociations.size() == 0) {
            logger.error("Error connecting to server, clientAssociations is empty!");
            if(integratedDataProcessing.selectDevice(addr.getHostAddress()) == null) {
                integratedDataProcessing.insertDevice(new DeviceList(addr.getHostAddress(), addr.getHostAddress(),port,false));
            }
            throw new Exception("错误连接到服务,客户端模型clientAssociations为空");
        }

        // 定义线程1
        Thread thread1 = new Thread() {
            public void run() {
                System.out.println("thread1...");
            }
        };

        //将设备添加到数据库
        if(integratedDataProcessing.selectDevice(addr.getHostAddress()) == null) {
            integratedDataProcessing.insertDevice(new DeviceList(addr.getHostAddress(), addr.getHostAddress(),port,true));
        }
    }

    public void retrieveServerModelByNet(InetAddress addr) throws Exception {
        //ServerModel serverModel;
        //从网络获取模型
        try {
            // requestModel() will call all GetDirectory and GetDefinition ACSI services needed to get the complete
            // server model
            clientServerModels.put(addr.getHostAddress(), clientAssociations.get(addr.getHostAddress()).retrieveModel());
        } catch (ServiceError e) {
            logger.error("Service Error requesting model.", e);
            clientAssociations.get(addr.getHostAddress()).close();
            throw  new Exception( "服务模型获取错误" + e);
        } catch (IOException e) {
            logger.error("Fatal IOException requesting model.", e);
            throw new Exception( "请求模型时IO异常");
        }

        // get the values of all data attributes in the model:
        try{
            clientAssociations.get(addr.getHostAddress()).getAllDataValues();
        }catch (Exception ex){
            logger.error("Error get data values.", ex);
        }
        for (BasicDataAttribute bda : clientServerModels.get(addr.getHostAddress()).getBasicDataAttributes()) {
            logger.info("BDA: " + bda);
        }

        for (Urcb urcb : clientServerModels.get(addr.getHostAddress()).getUrcbs()) {
            logger.info("URCB: " + urcb);
        }

        for (Brcb brcb : clientServerModels.get(addr.getHostAddress()).getBrcbs()) {
            logger.info("BRCB: " + brcb);
        }

        //将模型添加到数据库

    }

    /**
     * @function 与在线监测装置连接后通过本地SCL获取ServerModel进行关联
     * @param addr
     * @param icdPath
     */
    public void retrieveServerModelByScl(InetAddress addr, String icdPath) throws Exception {
        //ServerModel serverModel;
        //从ICD文件获取模型
        // instead of calling retrieveModel you could read the model directly from an SCL file:
        try {
            clientServerModels.put(addr.getHostAddress(), clientAssociations.get(addr.getHostAddress()).getModelFromIcdFile(icdPath));
        } catch (SclParseException e1) {
            logger.error("Error parsing SCL file.", e1);
            throw new SclParseException("错误解析SCL文件!");
        }

        // get the values of all data attributes in the model:
        try{
         //   clientAssociations.get(addr.getHostAddress()).getAllDataValues();
        }catch (Exception ex){
            logger.error("Error get data values.", ex);
            throw new Exception("错误获取在线检测设备值!");
        }

        for (BasicDataAttribute bda : clientServerModels.get(addr.getHostAddress()).getBasicDataAttributes()) {
            logger.info("BDA: " + bda);
        }

        for (Urcb urcb : clientServerModels.get(addr.getHostAddress()).getUrcbs()) {
            logger.info("URCB: " + urcb);
        }

        for (Brcb brcb : clientServerModels.get(addr.getHostAddress()).getBrcbs()) {
            logger.info("BRCB: " + brcb);
        }

        //将模型添加到数据库

    }


    /**
     * @function 与在线监测装置连接后通过网络获取ServerModel进行关联
     * @param addr
     * @param port
     */
    public void addClientAssociationByNets(ArrayList<InetAddress> addr, int port) throws Exception{
        //List<ClientSap> clientSap = new ArrayList<ClientSap>();
        // alternatively you could use ClientSap(SocketFactory factory) to e.g. connect using SSL
        // optionally you can set some association parameters (but usually the default should work):
        // clientSap.setTSelRemote(new byte[] { 0, 1 });
        // clientSap.setTSelLocal(new byte[] { 0, 0 });
        //ClientDataProcessing eventHandler = new ClientDataProcessing();
        //this.association = new ArrayList<ClientAssociation>();

        try {
            for(Iterator<InetAddress> it = addr.iterator(); it.hasNext();){
                clientAssociations.put(it.next().getHostAddress(), new ClientSap().associate(it.next(), port, null));
                logger.info("Attempting to connect to server " + addr.toString() + " on port " + port);
            }
            /*
            for(int i = 0; i < address.size(); i++){
                association.add(clientSap.associate(address.get(i), remotePort, null, eventHandler));
            }*/
        } catch (IOException e) {
            // an IOException will always indicate a fatal exception. It indicates that the association was closed and
            // cannot be recovered. You will need to create a new association using ClientSap.associate() in order to
            // reconnect.
            logger.error("Error connecting to server: " + e.getMessage());
            throw  new Exception( "错误连接到服务," + e.getMessage());
        }

        if(clientAssociations == null || clientAssociations.size() == 0) {
            logger.error("Error connecting to server, clientAssociations is empty!");
            throw  new Exception( "错误连接到服务,客户端模型clientAssociations为空");
        }

        //ServerModel serverModel;
        //从网络获取模型
        for(String key : clientAssociations.keySet()) {
            try {
                // requestModel() will call all GetDirectory and GetDefinition ACSI services needed to get the complete
                // server model
                clientServerModels.put(key, clientAssociations.get(key).retrieveModel());
            } catch (ServiceError e) {
                logger.error("Service Error requesting model.", e);
                clientAssociations.get(key).close();
                throw  new Exception( "服务模型获取错误" + e);
            } catch (IOException e) {
                logger.error("Fatal IOException requesting model.", e);
                throw new Exception( "请求模型时IO异常");
            }
        }

        // get the values of all data attributes in the model:
        for(String key : clientAssociations.keySet()) {
            try{
                clientAssociations.get(key).getAllDataValues();
            }catch (Exception ex){
                logger.error("Error get data values.", ex);
            }
        }
        for(String key : clientServerModels.keySet()) {
            for (BasicDataAttribute bda : clientServerModels.get(key).getBasicDataAttributes()) {
                logger.info("BDA: " + bda);
            }

            for (Urcb urcb : clientServerModels.get(key).getUrcbs()) {
                logger.info("URCB: " + urcb);
            }

            for (Brcb brcb : clientServerModels.get(key).getBrcbs()) {
                logger.info("BRCB: " + brcb);
            }
        }
    }

    public static Logger getLogger() {
        return logger;
    }

    public Map<String, ServerModel> getClientServerModels() {
        return clientServerModels;
    }

    public void setClientServerModels(Map<String, ServerModel> clientServerModels) {
        this.clientServerModels = clientServerModels;
    }

    public Map<String, ClientAssociation> getClientAssociations() {
        return clientAssociations;
    }

    public ClientAssociation getClientAssociation(String key) {
        return clientAssociations.get(key);
    }

    public void closedClientAssociation(String key) {
        clientAssociations.get(key).disconnect();
        clientAssociations.remove(key);
        integratedDataProcessing.deleteDevice(key);
    }

    public void setClientAssociations(Map<String, ClientAssociation> clientAssociations) {
        this.clientAssociations = clientAssociations;
    }

    public IntegratedDataProcessing getIntegratedDataProcessing() {
        return integratedDataProcessing;
    }

    public void setIntegratedDataProcessing(IntegratedDataProcessing integratedDataProcessing) {
        this.integratedDataProcessing = integratedDataProcessing;
    }
}
